using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
using System.Security.Cryptography;
using System.Data.SqlClient;
namespace SecurityService
{
    /// <summary>
    /// Summary description for Service1.
    /// </summary>
    public class LoginAuthentication : System.Web.Services.WebService
    {
        //		string connectionString = "Insert ConnectionString here";
        string connectionString = "Initial Catalog=MovieGuide;Data Source=localhost;user ID=sa;pwd=sasql";


        #region Component Designer generated code

        //Required by the Web Services Designer 
        private IContainer components = null;

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing && components != null)
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #endregion


        private RSACryptoServiceProvider crypt;

        public LoginAuthentication()
        {
            InitializeComponent();
            this.crypt = GetKeyFromState();

            //this.crypt = GetKeyFromState();
            //this.session = new VirtualWebDriveComponent.SecureServerSession(crypt);
        }
        [WebMethod()]
        public DateTime GetServerDate()
        {
            return DateTime.Now;
        }

        // Return the public portion of the key only.
        [WebMethod()]
        public string GetKey()
        {
            return crypt.ToXmlString(false);
        }
        [WebMethod()]
        public string Login(byte[] loginData)
        {
            SecurityComp.LoginInfo loginInfo = new SecurityComp.ClientSecurity(crypt).DecryptLoginData(loginData);
            int userID = ValidateLogin(loginInfo);

            if (userID == -1)
            {
                throw new ApplicationException("Cannot log in.");
            }

            // Create a new ticket.
            byte[] ticketBytes = new byte[16];
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            rng.GetBytes(ticketBytes);
            Guid ticketGuid = new Guid(ticketBytes);
            string ticket = ticketGuid.ToString();

            // Store this key in application state.
            Application[ticket] = new SecurityComp.TicketInfo(userID, this.Context.Request.UserHostAddress, loginInfo.ClientKey);

            // Return the ticket.
            return ticket;
        }

        [WebMethod()]
        public void Logout(string ticket)
        {
            Application.Remove(ticket);
        }
        public int ValidateLogin(SecurityComp.LoginInfo loginInfo)
        {
            if (loginInfo.CreatedTime.AddMinutes(5) < DateTime.Now ||
                loginInfo.CreatedTime > DateTime.Now)
            {
                throw new ApplicationException("Invalid login attempt.");
            }

            // Define the SQL string with named parameters.
            string SQL = "SELECT ID, UserName, Password From Users WHERE UserName=@UserName";
            SqlConnection con = new SqlConnection(connectionString);
            SqlCommand cmd = new SqlCommand(SQL, con);

            // Add the parameter values to the command.
            SqlParameter param;
            param = cmd.Parameters.Add("@UserName", SqlDbType.NChar, 50);
            param.Value = loginInfo.UserName;

            int userID = 0;
            byte[] passwordHash = null;
            try
            {
                con.Open();
                SqlDataReader r = cmd.ExecuteReader();

                if (r.Read())
                {
                    userID = (int)r["ID"];
                    passwordHash = (byte[])r["Password"];
                }
                else
                {
                    throw new ApplicationException("Invalid login attempt.");
                }
            }
            catch (Exception err)
            {
                // Log error here.
                System.Diagnostics.Debug.WriteLine(err.ToString());

                throw new ApplicationException("Database error.");
            }
            finally
            {
                con.Close();
            }

            // Verify the password hash.
            SecurityComp.HashHelper hashUtil = new SecurityComp.HashHelper();
            if (hashUtil.ComparePasswords(passwordHash, loginInfo.PasswordHash))
            {
                return userID;
            }
            else
            {
                throw new ApplicationException("Invalid login attempt.");
            }
        }
        private RSACryptoServiceProvider GetKeyFromState()
        {
            RSACryptoServiceProvider crypt = null;

            // Check if the key has been created yet.
            // This ensures that the key is only created once.
            if (Application["Key"] == null)
            {
                // Create a key for RSA encryption.
                CspParameters param = new CspParameters();
                param.Flags = CspProviderFlags.UseMachineKeyStore;
                crypt = new RSACryptoServiceProvider(param);

                // Store the key in the server memory.
                Application["Key"] = crypt;
            }
            else
            {
                crypt = (RSACryptoServiceProvider)Application["Key"];
            }
            return crypt;
        }


    }
}
